#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/platform_device.h>
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/dma-mapping.h>
#include <linux/dmaengine.h>
#include <linux/module.h>
#include <linux/err.h>
#include <linux/device.h>
#include <linux/completion.h>
#include <linux/delay.h>
#include <linux/random.h>
#include <linux/interrupt.h>
#include <linux/kthread.h>
#include <mach/debug.h>
#include <linux/of_reserved_mem.h>

/* redefine mode name, for PTR_XXX */
#undef MOD_NAME
#define MOD_NAME			"DMA_TEST"

/**
 * TEST_BY_KTHREAD:test switch for multi-channel paraller transmission.
 * if testing on FPGA platform, it's recommended to turn off this switch
 * 1:open
 * 0:close
 */
#define TEST_BY_KTHREAD			0

/* case1:slave transfer */
#define SLAVE_TRANSFER_COUNTS_1		(1024 * 1024 * 1)

/* case2:this is test the case that len is not aligned with src_width */
#define SLAVE_TRANSFER_COUNTS_2		(1024 * 1024 + 2)

/* case3:cyctic transfer */
#define CYCLIC_TRANSFER_COUNTS		(1024 * 1024 * 2)
#define CYCLIC_PERIOD_LEN		(1024 * 1024)
#define TRANSFER_COUNTS_PAUSE		10

/* case4:this case that len is not aligned with src_width and dst_widthe */
#define TRANSFER_COUNTS_999B		999

#define WIDTH_TYPE			3
#define TRANSFER_COUNTS_TERMINATE	10
#define COOKIE_STEP			1

typedef int (*test_item_t)(void *argc);

struct dma_test_data {
	struct device *dev;
	struct dma_chan *chan;
	dma_addr_t dma_src;
	dma_addr_t dma_dst;
	char *src;
	char *dst;
	int len;
};

struct test_cb_param {
	struct dma_test_data *dma_data;
	dma_cookie_t cookie;
};

unsigned long random_0;
unsigned char random_1;
static struct device *test_dev;
static DECLARE_COMPLETION(callback_complete_wait_1);
static DECLARE_COMPLETION(callback_complete_wait_2);
static DECLARE_COMPLETION(callback_complete_wait_3);
unsigned int case_counter_1;
unsigned int case_counter_2;
unsigned int case_counter_3;
int case_flag_1;
int case_flag_2;

int test_width[WIDTH_TYPE][2] = {
		{DMA_SLAVE_BUSWIDTH_2_BYTES, DMA_SLAVE_BUSWIDTH_4_BYTES},
		{DMA_SLAVE_BUSWIDTH_2_BYTES, DMA_SLAVE_BUSWIDTH_8_BYTES},
		{DMA_SLAVE_BUSWIDTH_4_BYTES, DMA_SLAVE_BUSWIDTH_8_BYTES} };

/*------------------------------test cases design-----------------------------*/
/**
 * 1. main thread: submit+pending, callback: submit+pending
 * 2. main thread: (submit+submit+pending), callback: (submit+pending)
 * 3. main thread: submit + pending + pause + resume + terminate
 *		   transtype: cyclic
 * 4. maim thread: data len is not aligned with src_width and dst_widthe
 *		   reulet: prepare desc failed
 *		   this case just for n7v5 n9
 */

static int init_dma_data(struct dma_test_data *dma_data, int len)
{
	dma_data->len = len;
	dma_data->dev = test_dev;
	dma_data->dma_src = 0;
	dma_data->dma_dst = 0;
	dma_data->chan = NULL;
	dma_data->src = NULL;
	dma_data->dst = NULL;

	dma_data->src = dma_alloc_coherent(dma_data->dev, dma_data->len,
					   &dma_data->dma_src, GFP_KERNEL);
	dma_data->dst = dma_alloc_coherent(dma_data->dev, dma_data->len,
					   &dma_data->dma_dst, GFP_KERNEL);

	if (!dma_data->src || !dma_data->dst) {
		if (dma_data->src)
			dma_free_coherent(dma_data->dev, dma_data->len,
					  dma_data->src, dma_data->dma_src);

		if (dma_data->dst)
			dma_free_coherent(dma_data->dev, dma_data->len,
					  dma_data->dst, dma_data->dma_dst);

		PRT_ERR("alloc coherent memory failed\n");
		return -ENOMEM;
	}

	return 0;
}

static void free_data(struct dma_test_data *dma_data)
{
	dma_data->chan = NULL;
	dma_data->dev = NULL;

	if (dma_data->src)
		dma_free_coherent(dma_data->dev, dma_data->len, dma_data->src,
				  dma_data->dma_src);

	if (dma_data->dst)
		dma_free_coherent(dma_data->dev, dma_data->len, dma_data->dst,
				  dma_data->dma_dst);

	devm_kfree(test_dev, dma_data);
}

static void init_config_data(struct dma_slave_config *dma_config,
				struct dma_test_data *dma_data)
{
	dma_config->direction = DMA_MEM_TO_MEM;
	dma_config->src_addr = dma_data->dma_src;
	dma_config->dst_addr = dma_data->dma_dst;
	dma_config->src_addr_width = DMA_SLAVE_BUSWIDTH_2_BYTES;
	dma_config->dst_addr_width = DMA_SLAVE_BUSWIDTH_2_BYTES;
	dma_config->src_maxburst = 4;
	dma_config->dst_maxburst = 4;
}

static void callback_func1(void *pparam)
{
	struct dma_async_tx_descriptor *tx;
	struct test_cb_param *cb_param;
	struct dma_test_data *dma_data;
	dma_cookie_t cookie;
	struct dma_device *dev;
	static dma_cookie_t precookie = DMA_MIN_COOKIE;

	cb_param = (struct test_cb_param *)pparam;
	dma_data = cb_param->dma_data;

	++case_counter_1;
	PRT_INFO("case_counter_1: %d\n", case_counter_1);

	if (case_counter_1 >= TRANSFER_COUNTS_TERMINATE) {
		precookie = DMA_MIN_COOKIE;
		complete(&callback_complete_wait_1);
		return;
	}

	if (cb_param->cookie == precookie + COOKIE_STEP) {
		/**
		 * adjust whether the number at random_0 in dst is equal
		 * to the number at ramdom_0 in src.
		 */
		if (random_1 == *(dma_data->dst + random_0) &&
			*(dma_data->dst + random_0) ==
					*(dma_data->src + random_0)) {
			/* successed */;
		} else {
			case_flag_1 = 1;
			PRT_ERR("data verify error, src:%d, dst:%d\n"
				"random0: %ld, ramdom1:%d, cookie: %d\n",
				*(dma_data->src + random_0),
				*(dma_data->dst + random_0),
				random_0, random_1, precookie + 1);
			complete(&callback_complete_wait_1);
			return;
		}
	} else {
		case_flag_1 = 1;
		PRT_ERR("cookie verify error: pre:%d, now:%d\n",
						precookie,
						cb_param->cookie);
		complete(&callback_complete_wait_1);
		return;
	}

	precookie = cb_param->cookie;

	/**
	 * here we should generate two random numbers, one represents
	 * the place in dst memory, the other is the number
	 * that will be set into this place.
	 */
	get_random_bytes(&random_0, sizeof(unsigned long));
	random_0 = random_0 % SLAVE_TRANSFER_COUNTS_1;
	get_random_bytes(&random_1, sizeof(unsigned char));
	*(dma_data->src + random_0) = random_1;

	/* get tx and submit */
	dev = dma_data->chan->device;
	if (dev->device_prep_dma_memcpy) {

		tx = dev->device_prep_dma_memcpy(dma_data->chan,
						 dma_data->dma_dst,
						 dma_data->dma_src,
						 dma_data->len,
						 DMA_CTRL_ACK);
		if (!tx) {
			case_flag_1 = 1;
			PRT_ERR("failed to prepare dma memcpy\n");
			complete(&callback_complete_wait_1);
			return;
		}
		tx->callback = callback_func1;
		cookie = tx->tx_submit(tx);
		cb_param->cookie = cookie;

		tx->callback_param = (void *)cb_param;

		if (dma_submit_error(cookie)) {
			case_flag_1 = 1;
			PRT_ERR("submit cookie failed\n");
			complete(&callback_complete_wait_1);
			return;
		}
		/* issue transfer */
		dma_async_issue_pending(dma_data->chan);
	}
}

static int main_thread_case1(void *argc)
{
	struct dma_async_tx_descriptor *tx;
	struct dma_device *dev;
	static dma_cookie_t cookie;
	struct dma_slave_config dma_config;
	struct dma_test_data *dma_data = NULL;
	struct test_cb_param *cb_param = NULL;
	int ret = 0;

	PRT_INFO("test case 1 start...\n");

	reinit_completion(&callback_complete_wait_1);

	dma_data = devm_kzalloc(test_dev, sizeof(*dma_data), GFP_KERNEL);
	cb_param = devm_kzalloc(test_dev, sizeof(*cb_param), GFP_KERNEL);
	if (!dma_data || !cb_param) {
		PRT_ERR("alloc dma_data or cb_param failed\n");
		return -ENOMEM;
	}

	ret = init_dma_data(dma_data, SLAVE_TRANSFER_COUNTS_1);
	if (ret) {
		PRT_ERR("init dma data failed\n");
		goto out;
	}

	/**
	 * here we should generate two random numbers, one represents
	 * the place in dst memory, the other is the number
	 * that will be set into this place.
	 */
	get_random_bytes(&random_0, sizeof(unsigned long));
	random_0 = random_0 % SLAVE_TRANSFER_COUNTS_1;
	get_random_bytes(&random_1, sizeof(unsigned char));
	*(dma_data->src + random_0) = random_1;

	dma_data->chan = dma_request_slave_channel(dma_data->dev,
						   "dmatest-rx");
	if (!dma_data->chan) {
		PRT_ERR("request channel failed\n");
		ret = -EBUSY;
		goto out;
	}

	init_config_data(&dma_config, dma_data);
	ret = dmaengine_slave_config(dma_data->chan, &dma_config);
	if (ret) {
		PRT_ERR("channel config failed\n");
		goto out;
	}

	/* get tx and submit */
	dev = dma_data->chan->device;
	if (dev->device_prep_dma_memcpy) {

		tx = dev->device_prep_dma_memcpy(dma_data->chan,
						 dma_data->dma_dst,
						 dma_data->dma_src,
						 dma_data->len,
						 DMA_CTRL_ACK);
		if (!tx) {
			PRT_ERR("failed to prepare dma memcpy\n");
			ret = -EBUSY;
			goto out;
		}

		cookie = tx->tx_submit(tx);

		cb_param->cookie = cookie;
		cb_param->dma_data = dma_data;
		tx->callback = callback_func1;
		tx->callback_param = (void *)cb_param;

		if (dma_submit_error(cookie)) {
			PRT_ERR("submit cookie failed\n");
			ret = -EBUSY;
			goto out;
		}
		/* issue transfer */
		dma_async_issue_pending(dma_data->chan);
	}

	PRT_INFO("waitting complete...\n");
	wait_for_completion(&callback_complete_wait_1);

	/*
	 * for our current test case, we need to make the tasklet
	 * callback in func dmaengine_terminate_all completed as
	 * soon as possible, the below code need to be added.
	 */
	/* disbale the softirq in critical area */
	local_bh_disable();

	dmaengine_terminate_all(dma_data->chan);

	/* release the bh lock, this can make the tasklet callback
	 * be called
	 */
	local_bh_enable();

out:
	if (dma_data->chan)
		dma_release_channel(dma_data->chan);
	free_data(dma_data);
	devm_kfree(test_dev, cb_param);

	if (ret || case_flag_1)
		PRT_ERR("test case 1 failed\n");
	else
		PRT_INFO("test case 1 pass\n");

	return (ret | case_flag_1);
}

static void callback_func2(void *pparam)
{
	struct dma_async_tx_descriptor *tx;
	struct test_cb_param *cb_param;
	struct dma_test_data *dma_data;
	struct dma_device *dev;
	static dma_cookie_t cookie;
	static dma_cookie_t precookie = DMA_MIN_COOKIE;

	cb_param = (struct test_cb_param *)pparam;
	dma_data = cb_param->dma_data;

	++case_counter_2;
	PRT_INFO("case_counter_2:%d\n", case_counter_2);

	if (case_counter_2 >= TRANSFER_COUNTS_TERMINATE) {
		precookie = DMA_MIN_COOKIE;
		complete(&callback_complete_wait_2);
		return;
	}

	if (cb_param->cookie == precookie + COOKIE_STEP) {
		;
	} else {
		case_flag_2 = 1;
		PRT_ERR("cookie verify error: pre:%d, now:%d\n",
					precookie,
					cb_param->cookie);
		complete(&callback_complete_wait_2);
		return;
	}

	precookie = cb_param->cookie;

	/* get tx and submit */
	dev = dma_data->chan->device;
	if (dev->device_prep_dma_memcpy) {

		tx = dev->device_prep_dma_memcpy(dma_data->chan,
						 dma_data->dma_dst,
						 dma_data->dma_src,
						 dma_data->len,
						 DMA_CTRL_ACK);
		if (!tx) {
			case_flag_2 = 1;
			PRT_ERR("failed to prepare dma memcpy\n");
			complete(&callback_complete_wait_2);
			return;
		}

		cookie = tx->tx_submit(tx);

		cb_param->cookie = cookie;
		tx->callback = callback_func2;
		tx->callback_param = (void *)cb_param;

		if (dma_submit_error(cookie)) {
			case_flag_2 = 1;
			PRT_ERR("submit cookie failed\n");
			complete(&callback_complete_wait_2);
			return;
		}

		/* issue transfer */
		dma_async_issue_pending(dma_data->chan);
	}
}

static int main_thread_case2(void *argc)
{
	struct dma_async_tx_descriptor *tx;
	struct dma_async_tx_descriptor *tx1;
	struct dma_device *dev;
	static dma_cookie_t cookie;
	static dma_cookie_t cookie1;
	struct dma_slave_config dma_config;
	struct dma_test_data *dma_data = NULL;
	struct test_cb_param *cb_param = NULL;
	struct test_cb_param *cb_param1 = NULL;
	int ret = 0;

	PRT_INFO("test case 2 start...\n");

	reinit_completion(&callback_complete_wait_2);

	dma_data = devm_kzalloc(test_dev, sizeof(*dma_data), GFP_KERNEL);
	cb_param = devm_kzalloc(test_dev, sizeof(*cb_param), GFP_KERNEL);
	cb_param1 = devm_kzalloc(test_dev, sizeof(*cb_param1), GFP_KERNEL);
	if (!dma_data || !cb_param || !cb_param1) {
		PRT_ERR("alloc dma_data or cb_param failed\n");
		return -ENOMEM;
	}

	ret = init_dma_data(dma_data, SLAVE_TRANSFER_COUNTS_2);
	if (ret) {
		PRT_ERR("init dma data failed\n");
		goto out;
	}

	dma_data->chan = dma_request_slave_channel(dma_data->dev, "dmatest-rx");
	if (!dma_data->chan) {
		PRT_ERR("request channel failed\n");
		return -EBUSY;
	}

	init_config_data(&dma_config, dma_data);
	ret = dmaengine_slave_config(dma_data->chan, &dma_config);
	if (ret) {
		PRT_ERR("channel config failed\n");
		goto out;
	}

	/* get tx and submit */
	dev = dma_data->chan->device;
	if (dev->device_prep_dma_memcpy) {

		tx = dev->device_prep_dma_memcpy(dma_data->chan,
						 dma_data->dma_dst,
						 dma_data->dma_src,
						 dma_data->len,
						 DMA_CTRL_ACK);
		if (!tx) {
			PRT_ERR("failed to prepare dma memcpy\n");
			ret = -EBUSY;
			goto out;
		}

		cookie = tx->tx_submit(tx);

		cb_param->cookie = cookie;
		cb_param->dma_data = dma_data;
		tx->callback = callback_func2;
		tx->callback_param = (void *)cb_param;

		if (dma_submit_error(cookie)) {
			PRT_ERR("submit cookie failed\n");
			ret = -EBUSY;
			goto out;
		}

		/* submit the sencond times*/
		tx1 = dev->device_prep_dma_memcpy(dma_data->chan,
						 dma_data->dma_dst,
						 dma_data->dma_src,
						 dma_data->len,
						 DMA_CTRL_ACK);
		if (!tx1) {
			PRT_ERR("failed to prepare dma memcpy\n");
			ret = -EBUSY;
			goto out;
		}

		cookie1 = tx1->tx_submit(tx1);

		cb_param1->cookie = cookie1;
		cb_param1->dma_data = dma_data;
		tx1->callback = callback_func2;
		tx1->callback_param = (void *)cb_param1;

		if (dma_submit_error(cookie1)) {
			PRT_ERR("submit cookie failed\n");
			ret = -EBUSY;
			goto out;
		}
		/* issue transfer */
		dma_async_issue_pending(dma_data->chan);
	}

	wait_for_completion(&callback_complete_wait_2);

	/*
	 * for our current test case, we need to make the tasklet
	 * callback in func dmaengine_terminate_all completed as
	 * soon as possible, the below code need to be added.
	 */
	/* disable the softirq in critical area */
	local_bh_disable();

	dmaengine_terminate_all(dma_data->chan);

	/* release the bh lock, this can make the tasklet callback
	 * be called
	 */
	local_bh_enable();

out:
	if (dma_data->chan)
		dma_release_channel(dma_data->chan);
	free_data(dma_data);
	devm_kfree(test_dev, cb_param);
	devm_kfree(test_dev, cb_param1);

	if (ret || case_flag_2)
		PRT_ERR("test case 2 failed\n");
	else
		PRT_INFO("test case 2 pass\n");

	return (ret | case_flag_2);
}

static void callback_func3(void *pparam)
{
	struct test_cb_param *cb_param;
	struct dma_test_data *dma_data;

	cb_param = (struct test_cb_param *)pparam;
	dma_data = cb_param->dma_data;

	++case_counter_3;
	PRT_INFO("case_counter_3: %d\n", case_counter_3);

	if (case_counter_3 == TRANSFER_COUNTS_PAUSE) {
		dmaengine_pause(dma_data->chan);
		PRT_INFO("dma control pause,waitting 3s ...\n");
		mdelay(3000);

		dmaengine_resume(dma_data->chan);
		PRT_INFO("dma control resume\n");
	}

	if (case_counter_3 == TRANSFER_COUNTS_TERMINATE) {
		dmaengine_terminate_sync(dma_data->chan);
		PRT_INFO("dma control terminate\n");

		complete(&callback_complete_wait_3);
	}
}

static int main_thread_case3(void *argc)
{
	struct dma_async_tx_descriptor *tx;
	struct dma_device *dev;
	static dma_cookie_t cookie;
	struct dma_slave_config dma_config;
	struct dma_test_data *dma_data = NULL;
	struct test_cb_param *cb_param = NULL;
	int ret = 0;

	PRT_INFO("test case 3 start...\n");

	reinit_completion(&callback_complete_wait_3);

	dma_data = devm_kzalloc(test_dev, sizeof(*dma_data), GFP_KERNEL);
	cb_param = devm_kzalloc(test_dev, sizeof(*cb_param), GFP_KERNEL);
	if (!dma_data || !cb_param) {
		PRT_ERR("alloc dma_data or cb_param failed\n");
		return -ENOMEM;
	}

	ret = init_dma_data(dma_data, CYCLIC_TRANSFER_COUNTS);
	if (ret) {
		PRT_ERR("init dma data failed\n");
		goto out;
	}

	dma_data->chan = dma_request_slave_channel(dma_data->dev, "dmatest-rx");
	if (!dma_data->chan) {
		PRT_ERR("request channel failed\n");
		ret = -EBUSY;
		goto out;
	}

	init_config_data(&dma_config, dma_data);
	ret = dmaengine_slave_config(dma_data->chan, &dma_config);
	if (ret) {
		PRT_ERR("channel config failed\n");
		goto out;
	}

	/* get tx and submit */
	dev = dma_data->chan->device;
	if (dev->device_prep_dma_cyclic) {

		tx = dev->device_prep_dma_cyclic(dma_data->chan,
						 dma_data->dma_src,
						 dma_data->len,
						 CYCLIC_PERIOD_LEN,
						 DMA_MEM_TO_MEM,
						 DMA_CTRL_ACK);
		if (!tx) {
			PRT_ERR("failed to prepare dma memcpy\n");
			ret = -EBUSY;
			goto out;
		}

		cookie = tx->tx_submit(tx);

		cb_param->cookie = cookie;
		cb_param->dma_data = dma_data;
		tx->callback = callback_func3;
		tx->callback_param = (void *)cb_param;

		if (dma_submit_error(cookie)) {
			PRT_ERR("submit cookie failed\n");
			ret = -EBUSY;
			goto out;
		}
		/* issue transfer */
		dma_async_issue_pending(dma_data->chan);
	}

	PRT_INFO("waitting completion...\n");
	wait_for_completion(&callback_complete_wait_3);

	/*
	 * for our current test case, we need to make the tasklet
	 * callback in func dmaengine_terminate_all completed as
	 * soon as possible, the below code need to be added.
	 */
	/* disbale the softirq in critical area */
	local_bh_disable();

	dmaengine_terminate_all(dma_data->chan);

	/* release the bh lock, this can make the tasklet callback
	 * be called
	 */
	local_bh_enable();

out:

	if (dma_data->chan)
		dma_release_channel(dma_data->chan);

	if (ret)
		PRT_ERR("test case 3 failed\n");
	else
		PRT_INFO("test case 3 pass\n");

	return ret;
}

#ifdef CONFIG_ARCH_LOMBO_N7V5
static int main_thread_case4(void)
{
	struct dma_async_tx_descriptor *tx;
	struct dma_device *dev;
	struct dma_slave_config dma_config;
	struct dma_test_data *dma_data = NULL;
	int i;
	int ret = 0;

	PRT_INFO("test case 4 start...\n");

	dma_data = devm_kzalloc(test_dev, sizeof(*dma_data), GFP_KERNEL);
	if (!dma_data) {
		PRT_ERR("alloc dma_data failed\n");
		return -ENOMEM;
	}

	ret = init_dma_data(dma_data, TRANSFER_COUNTS_999B);
	if (ret) {
		PRT_ERR("init dma_data failed\n");
		goto out;
	}

	dma_data->chan = dma_request_slave_channel(dma_data->dev, "dmatest-rx");
	if (!dma_data->chan) {
		PRT_ERR("request channel failed\n");
		ret = -EBUSY;
		goto out;
	}

	init_config_data(&dma_config, dma_data);

	/* get tx and submit */
	dev = dma_data->chan->device;
	if (dev->device_prep_dma_memcpy) {

		for (i = 0; i < WIDTH_TYPE; i++) {
			dma_config.src_addr_width = test_width[i][0];
			dma_config.dst_addr_width = test_width[i][1];

			ret = dmaengine_slave_config(dma_data->chan,
						     &dma_config);
			if (ret) {
				PRT_ERR("channel config failed\n");
				goto out;
			}

			tx = dev->device_prep_dma_memcpy(dma_data->chan,
							dma_data->dma_dst,
							dma_data->dma_src,
							dma_data->len,
							DMA_CTRL_ACK);
			if (!tx) {
				PRT_INFO("%d:prepare dma memcpy failed\n", i+1);
			} else {
				PRT_ERR("case4: failed\n");
				complete(&callback_complete_wait);
				goto out;
			}
		}
	}

out:
	if (dma_data->chan)
		dma_release_channel(dma_data->chan);
	free_data(dma_data);

	if (ret)
		PRT_INFO("test case 4 failed\n");
	else
		PRT_INFO("test case 4 pass\n");

	return ret;
}
#endif

/* add test class here */
static test_item_t test_item[] = {
	main_thread_case1,
	main_thread_case2,
	main_thread_case3,
#ifdef CONFIG_ARCH_LOMBO_N7V5
	main_thread_case4,
#endif
};

void dma_test(void)
{
	int i;
	int ret = 0;
	int err_counts = 0;
	struct task_struct *case_task_1;
	struct task_struct *case_task_2;
	struct task_struct *case_task_3;

	PRT_INFO("---------------- DMA TEST START... ----------------\n");

#if TEST_BY_KTHREAD
	case_task_1 = kthread_create(main_thread_case1, NULL, "case_task_1");
	case_task_2 = kthread_create(main_thread_case2, NULL, "case_task_2");
	case_task_3 = kthread_create(main_thread_case3, NULL, "case_task_3");
	if (IS_ERR(case_task_1) || IS_ERR(case_task_2) || IS_ERR(case_task_3)) {
		PRT_ERR("kthread_create failed\n");
		return;
	}

	wake_up_process(case_task_1);
	wake_up_process(case_task_2);
	wake_up_process(case_task_3);
#else
	for (i = 0; i < ARRAY_SIZE(test_item); i++) {
		ret = test_item[i](NULL);
		if (ret) {
			PRT_ERR("case %d test failed\n", i+1);
			err_counts++;
		}
	}
#endif

	PRT_INFO("------------------- DMA TEST END -------------------\n");

	if (err_counts != 0)
		PRT_INFO("TEST RESULT: FAILED,ERR COUNTS: %d\n", err_counts);
	else
		PRT_INFO("TEST RESULT: SUCCESS!\n");
}

static int dma_test_probe(struct platform_device *pdev)
{
	int ret = 0;

#if defined(CONFIG_ARCH_LOMBO_N5V1)
	ret = of_reserved_mem_device_init(&pdev->dev);
	if (ret < 0)
		PRT_ERR("bindding dev to coherent mem failed\n");
#endif

	test_dev = &pdev->dev;

	PRT_INFO("dma test driver probe success\n");

	return ret;
}

static int dma_test_remove(struct platform_device *pdev)
{
	PRT_INFO("dma test driver remove\n");
	return 0;
}

static const struct of_device_id dma_test_match[] = {
	{ .compatible = "dma-test", },
	{},
};
MODULE_DEVICE_TABLE(of, dma_test_match);

static struct platform_driver dma_test_platform_driver = {
	.probe  = dma_test_probe,
	.remove = dma_test_remove,
	.driver = {
		.name  = "dma-test",
		.owner = THIS_MODULE,
		.of_match_table = dma_test_match,
	},
};

static int __init dma_test_init(void)
{
	return platform_driver_register(&dma_test_platform_driver);
}
subsys_initcall_sync(dma_test_init);

MODULE_DESCRIPTION("LomboTech DMA test Driver");
MODULE_AUTHOR("LomboTech Co.Ltd");
MODULE_LICENSE("GPL");
